﻿using System;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.Text.Editor;
using System.Windows.Input;
using System.Windows;
using Microsoft.VisualStudio.Text;

namespace XCopy
{
    [Export(typeof(IWpfTextViewCreationListener))]
    [ContentType("text")]
    [TextViewRole(PredefinedTextViewRoles.Document)]
    internal class XCopy : IWpfTextViewCreationListener
    {
        private string _selectionText;

        public void TextViewCreated(IWpfTextView textView)
        {
            textView.VisualElement.MouseDown += VisualElement_MouseDown;
            textView.VisualElement.MouseUp += VisualElement_MouseUp;
        }

        private void VisualElement_MouseUp(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            IWpfTextView textView = sender as IWpfTextView;
            if ((textView == null) || (element == null))
            {
                return;
            }
            if (e.ChangedButton == MouseButton.Left)
            {
                ITextSelection selection = textView.Selection;
                var spans = selection.SelectedSpans;
                foreach (SnapshotSpan span in spans)
                {
                    var text = span.GetText();
                    if (text.Length > 0)
                    {
                        _selectionText = text;
                        break;
                    }
                }
            }
        }

        private void VisualElement_MouseDown(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            IWpfTextView textView = sender as IWpfTextView;
            if ((textView == null) || (element == null))
            {
                return;
            }
            if ((e.ChangedButton == MouseButton.Middle) && (_selectionText.Length > 0))
            {
                if (e.LeftButton == MouseButtonState.Released)
                {
                    simulateLeftClick(element, e.MouseDevice, e.Source);
                    var caretPosition = textView.Caret.Position.BufferPosition;
                    var textEdit = textView.TextBuffer.CreateEdit();
                    textEdit.Insert(caretPosition, _selectionText);
                    textEdit.Apply();
                }
                else
                {
                    ITextSelection selection = textView.Selection;
                    var spans = selection.SelectedSpans;
                    foreach (SnapshotSpan span in spans)
                    {
                        var textEdit = textView.TextBuffer.CreateEdit();
                        textEdit.Replace(span.Start, span.Length, _selectionText);
                        textEdit.Apply();
                        break;
                    }
                }
            }
        }

        private void simulateLeftClick(FrameworkElement element, MouseDevice mouseDevice, object source)
        {
            MouseButtonEventArgs downArgs = new MouseButtonEventArgs(mouseDevice, new TimeSpan(DateTime.Now.Ticks).Milliseconds, MouseButton.Left)
            {
                RoutedEvent = UIElement.MouseDownEvent,
                Source = source
            };
            element.RaiseEvent(downArgs);
            MouseButtonEventArgs upArgs = new MouseButtonEventArgs(mouseDevice, new TimeSpan(DateTime.Now.Ticks).Milliseconds, MouseButton.Left)
            {
                RoutedEvent = UIElement.MouseUpEvent,
                Source = source
            };
            element.RaiseEvent(upArgs);
        }
    }
}
